import axios, { Canceler } from 'axios';
import { message, Modal } from 'ant-design-vue';
import type { AxiosRequestConfig } from 'axios';
import { AUTH_TOKEN_KEY } from '@/enums/cacheEnum';
import { Storage } from '@/utils/Storage';
import { uniqueSlash } from '@/utils/urlUtils';
import { ResultEnum } from '@/enums/httpEnum';

export interface RequestOptions {
  /** 当前接口权限, 不需要鉴权的接口请忽略， 格式：sys:user:add */
  permCode?: string;
  /** 是否直接获取data，而忽略message等 */
  isGetDataDirectly?: boolean;
  /** 请求成功是提示信息 */
  successMsg?: string;
  /** 请求失败是提示信息 */
  errorMsg?: string;
}

const UNKNOWN_ERROR = '服务器连接失败，请重试';

/** 真实请求的路径前缀 */
export const baseApiUrl = import.meta.env.VITE_BASE_API;

const service = axios.create({
  // baseURL: baseApiUrl,
  timeout: 6000,
});

const CancelToken = axios.CancelToken;
let cancel: Canceler;

service.interceptors.request.use(
  (config) => {
    const token = Storage.get(AUTH_TOKEN_KEY);
    if (token && config.headers) {
      // 请求头token信息
      config.headers['adminAuthToken'] = token;
    }
    // 在发送请求前添加cancelToken
    config.cancelToken = new CancelToken((c) => {
      cancel = c;
    });
    return config;
  },
  (error) => {
    Promise.reject(error);
  },
);

service.interceptors.response.use(
  (response) => {
    const res = response.data;
    if (res.code !== ResultEnum.SUCCESS) {
      message.error(res.msg || UNKNOWN_ERROR);
      if (res.code === ResultEnum.NOLOGIN) {
        cancel && cancel();
        Storage.clear();
        Modal.confirm({
          title: '警告',
          content: res.msg || '账号异常，您可以取消停留在该页上，或重新登录',
          okText: '重新登录',
          cancelText: '取消',
          onOk: () => {
            Storage.clear();
            window.location.reload();
          },
        });
      }
      return false;
    } else {
      return res;
    }
  },
  (error) => {
    // 服务器请求500的错误异常提示
    const errMsg = error?.response?.data?.message ?? UNKNOWN_ERROR;
    message.error(errMsg);
    error.message = errMsg;
    console.info('response error:', error);
    return Promise.reject(error);
  },
);

export type Response<T = any> = {
  code: number;
  msg: string;
  data: T;
};

export type BaseResponse<T = any> = Promise<Response<T>>;

/**
 *
 * @param config { method: request methods, url: request url, data: request data or params }
 * @param options RequestOptions
 */
export const request = async <T = any>(
  config: AxiosRequestConfig,
  options: RequestOptions = {},
): Promise<T> => {
  try {
    const { isGetDataDirectly = false } = options;
    const fullUrl = `${baseApiUrl + config.url}`;
    config.url = uniqueSlash(fullUrl);
    const res = await service.request(config);
    return isGetDataDirectly ? res.data : res;
  } catch (error: any) {
    console.info('request error:', error);
    return Promise.reject(error);
  }
};
